home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Online / opennap / network.c < prev    next >
C/C++ Source or Header  |  2001-06-08  |  12KB  |  505 lines

  1. /* Copyright (C) 2000-1 drscholl@users.sourceforge.net
  2.    This is free software distributed under the terms of the
  3.    GNU Public License.  See the file COPYING for details.
  4.  
  5.    $Id: network.c,v 1.42 2001/02/15 08:39:45 drscholl Exp $ */
  6.  
  7. /* Modified 30/05/01 : Removed dependency on RLIMIT_FD_MAX, which is undefined
  8.                        in the Amiga GCC 2.7.0 includes
  9.  
  10.                        Added defines for ntohl(), ntohs() and htons() which
  11.                        are not defined in the Amiga GCC 2.7.0 includes
  12.  
  13.                        Added include "extrasocket.h" with inlines for a few
  14.                        bsdsocket.library functions not emulated by ixemul
  15. */
  16.  
  17. #define ntohl(x) (x)
  18. #define ntohs(x) (x)
  19. #define htons(x) (x)
  20.  
  21. #include <errno.h>
  22. #include <string.h>
  23. #include <fcntl.h>
  24. #include <ctype.h>
  25. #if !defined(WIN32) || defined(__CYGWIN__)
  26. #include <sys/socket.h>
  27. #include <unistd.h>
  28. #include <netinet/in.h>
  29. #include <arpa/inet.h>
  30. #include <sys/types.h>
  31. #include <netdb.h>
  32. #include <sys/time.h>
  33. #include <sys/resource.h>
  34. #endif /* !WIN32 */
  35. #include "opennap.h"
  36. #include "debug.h"
  37.  
  38. #include "extrasocket.h"
  39.  
  40. /* solaris 2.6 doesn't seem to define this */
  41. #ifndef INADDR_NONE
  42. #define INADDR_NONE 0xffffffff
  43. #endif
  44.  
  45. unsigned int
  46. lookup_ip (const char *host)
  47. {
  48.     struct hostent *he;
  49.     unsigned int ip;
  50.  
  51.     log ("lookup_ip: resolving %s", host);
  52.     /* check for dot-quad notation.  Win95's gethostbyname() doesn't seem
  53.        to return the ip address properly for this case like every other OS */
  54.     ip = inet_addr (host);
  55.     if (ip == INADDR_NONE)
  56.     {
  57.         he = gethostbyname (host);
  58.         if (!he)
  59.         {
  60.             log ("lookup_ip: can't find ip for host %s", host);
  61.             return 0;
  62.         }
  63.         memcpy (&ip, he->h_addr_list[0], he->h_length);
  64.     }
  65.     log ("lookup_ip: %s is %s", host, my_ntoa (ip));
  66.     return ip;
  67. }
  68.  
  69. int
  70. set_nonblocking (int f)
  71. {
  72.     /* set the socket to be nonblocking */
  73. #if !defined(WIN32) || defined(__CYGWIN__)
  74.     if (fcntl (f, F_SETFL, O_NONBLOCK) != 0)
  75. #else
  76.     int     val = 1;
  77.  
  78.     if (ioctlsocket (f, FIONBIO, &val) != 0)
  79. #endif /* !WIN32 */
  80.     {
  81.         log ("set_nonblocking: fcntl: %s", strerror (errno));
  82.         return -1;
  83.     }
  84.     return 0;
  85. }
  86.  
  87. int
  88. set_tcp_buffer_len (int f, int bytes)
  89. {
  90.     if (setsockopt
  91.         (f, SOL_SOCKET, SO_SNDBUF, SOCKOPTCAST & bytes, sizeof (bytes)) == -1)
  92.     {
  93.         log ("set_tcp_buffer_len: setsockopt: %s (errno %d)",
  94.              strerror (errno), errno);
  95.         return -1;
  96.     }
  97.     if (setsockopt
  98.         (f, SOL_SOCKET, SO_RCVBUF, SOCKOPTCAST & bytes, sizeof (bytes)) == -1)
  99.     {
  100.         log ("set_tcp_buffer_len: setsockopt: %s (errno %d)",
  101.              strerror (errno), errno);
  102.         return -1;
  103.     }
  104.     return 0;
  105. }
  106.  
  107. int
  108. new_tcp_socket (int options)
  109. {
  110.     int     f;
  111.  
  112.     f = socket (AF_INET, SOCK_STREAM, 0);
  113.     if (f < 0)
  114.     {
  115.         logerr ("new_tcp_socket", "socket");
  116.         return -1;
  117.     }
  118.     if (options & ON_NONBLOCKING)
  119.     {
  120.         if (set_nonblocking (f))
  121.         {
  122.             CLOSE (f);
  123.             return -1;
  124.         }
  125.     }
  126.     if (options & ON_REUSEADDR)
  127.     {
  128.         int     i = 1;
  129.  
  130.         if (setsockopt
  131.             (f, SOL_SOCKET, SO_REUSEADDR, SOCKOPTCAST & i, sizeof (i)) != 0)
  132.         {
  133.             CLOSE (f);
  134.             nlogerr ("new_tcp_socket", "setsockopt");
  135.             exit (1);
  136.         }
  137.     }
  138.     return f;
  139. }
  140.  
  141. int
  142. set_keepalive (int f, int on)
  143. {
  144.     if (setsockopt
  145.         (f, SOL_SOCKET, SO_KEEPALIVE, SOCKOPTCAST & on, sizeof (on)) == -1)
  146.     {
  147.         log ("set_keepalive: setsockopt: %s (errno %d).",
  148.              strerror (errno), errno);
  149.         return -1;
  150.     }
  151.     return 0;
  152. }
  153.  
  154. int
  155. bind_interface (int fd, unsigned int ip, int port)
  156. {
  157.     struct sockaddr_in sin;
  158.  
  159.     memset (&sin, 0, sizeof (sin));
  160.     sin.sin_family = AF_INET;
  161.     sin.sin_addr.s_addr = ip;
  162.     sin.sin_port = htons (port);
  163.     if (bind (fd, (struct sockaddr *) &sin, sizeof (sin)) < 0)
  164.     {
  165.         nlogerr ("bind_interface", "bind");
  166.         return -1;
  167.     }
  168.     return 0;
  169. }
  170.  
  171. int
  172. make_tcp_connection (const char *host, int port, unsigned int *ip)
  173. {
  174.     struct sockaddr_in sin;
  175.     int     f;
  176.  
  177.     memset (&sin, 0, sizeof (sin));
  178.     sin.sin_port = htons (port);
  179.     sin.sin_family = AF_INET;
  180.     if ((sin.sin_addr.s_addr = lookup_ip (host)) == 0)
  181.         return -1;
  182.     if (ip)
  183.         *ip = sin.sin_addr.s_addr;
  184.     if ((f = new_tcp_socket (ON_NONBLOCKING)) == -1)
  185.         return -1;
  186.  
  187.     /* if an interface was specify, bind to it before connecting */
  188.     if (Interface)
  189.         bind_interface (f, Interface, 0);
  190.  
  191.     /* turn on TCP/IP keepalive messages */
  192.     set_keepalive (f, 1);
  193.     log ("make_tcp_connection: connecting to %s:%hu",
  194.          inet_ntoa (sin.sin_addr), ntohs (sin.sin_port));
  195.     if (connect (f, (struct sockaddr *) &sin, sizeof (sin)) < 0)
  196.     {
  197.         if (N_ERRNO != EINPROGRESS
  198. #ifdef WIN32
  199.             /* winsock returns EWOULDBLOCK even in nonblocking mode! ugh!!! */
  200.             && N_ERRNO != EWOULDBLOCK
  201. #endif
  202.             )
  203.         {
  204.             nlogerr ("make_tcp_connection", "connect");
  205.             CLOSE (f);
  206.             return -1;
  207.         }
  208.         log ("make_tcp_connection: connection to %s in progress", host);
  209.     }
  210.     else
  211.         log ("make_tcp_connection: connection established to %s", host);
  212.     return f;
  213. }
  214.  
  215. int
  216. check_connect_status (int f)
  217. {
  218.     socklen_t len;
  219.     int     err;
  220.  
  221.     len = sizeof (err);
  222.  
  223.     if (getsockopt (f, SOL_SOCKET, SO_ERROR, SOCKOPTCAST & err, &len) != 0)
  224.     {
  225.         nlogerr ("check_connect_status", "getsockopt");
  226.         return -1;
  227.     }
  228.     if (err != 0)
  229.     {
  230.         _logerr ("check_connect_status", "connect", err);
  231.         return -1;
  232.     }
  233.     return 0;
  234. }
  235.  
  236. char   *
  237. my_ntoa (unsigned int ip)
  238. {
  239.     struct in_addr a;
  240.  
  241.     a.s_addr = ip;
  242.     return (inet_ntoa (a));
  243. }
  244.  
  245. #if !defined(WIN32) && !defined(__EMX__)
  246.  
  247. #ifdef RLIMIT_FDMAX
  248. # define RLIMIT_FD_MAX   RLIMIT_FDMAX
  249. #else
  250. # ifdef RLIMIT_NOFILE
  251. #  define RLIMIT_FD_MAX RLIMIT_NOFILE
  252. # else
  253. #  ifdef RLIMIT_OPEN_MAX
  254. #   define RLIMIT_FD_MAX RLIMIT_OPEN_MAX
  255. #  else
  256. #   undef RLIMIT_FD_MAX
  257. #  endif
  258. # endif
  259. #endif
  260.  
  261. static int
  262. set_limit (int attr, int value)
  263. {
  264.     struct rlimit lim;
  265.  
  266.     if (getrlimit (attr, &lim))
  267.     {
  268.         logerr ("set_limit_size", "getrlimit");
  269.         return -1;
  270.     }
  271.     if (lim.rlim_max > 0 && value > lim.rlim_max)
  272.     {
  273.         /* give feedback to the operator if the default value is lower than
  274.            requested.  this is important when making the decision as to wheter
  275.            or not the server needs to be run as uid 0 */
  276.         log ("set_limit(): warning: %d exceeds default hard limit of %d",
  277.              value, lim.rlim_max);
  278.     }
  279.     lim.rlim_cur = value;
  280.     if (lim.rlim_max > 0 && lim.rlim_cur > lim.rlim_max)
  281.         lim.rlim_max = lim.rlim_cur;    /* adjust max value */
  282. #ifndef HAVE_POLL
  283. /*    if (attr == RLIMIT_FD_MAX && lim.rlim_cur > FD_SETSIZE)
  284.     {
  285.         log
  286.             ("set_limit(): warning: compiled limit (%d) is smaller than hard limit (%d)",
  287.              FD_SETSIZE, lim.rlim_max);
  288.     }*/
  289. #endif /* HAVE_POLL */
  290.     if (setrlimit (attr, &lim))
  291.     {
  292.         logerr ("set_limit", "setrlimit");
  293.         return -1;
  294.     }
  295.     return 0;
  296. }
  297.  
  298. int
  299. set_max_connections (int n)
  300. {
  301.     if (set_limit (/*RLIMIT_FD_MAX*/0, n))
  302.     {
  303.         log ("set_max_connections: unable to set resource limit");
  304.         return -1;
  305.     }
  306.     log ("set_max_connections: max connections set to %d", n);
  307.     return 0;
  308. }
  309.  
  310. int
  311. set_data_size (int n)
  312. {
  313.     if (set_limit (RLIMIT_DATA, n))
  314.     {
  315.         log ("set_data_size: unable to set resource limit");
  316.         return -1;
  317.     }
  318.     log ("set_data_size: max data segment size set to %d", n);
  319.     return 0;
  320. }
  321.  
  322. /* SysVR4 uses RLIMIT_AS (eg. Solaris) */
  323. #ifndef RLIMIT_RSS
  324. #define RLIMIT_RSS RLIMIT_AS
  325. #endif
  326.  
  327. int
  328. set_rss_size (int n)
  329. {
  330.     if (set_limit (RLIMIT_RSS, n))
  331.     {
  332.         log ("set_rss_size: unable to set resource limit");
  333.         return -1;
  334.     }
  335.     log ("set_rss_size: max rss segment size set to %d", n);
  336.     return 0;
  337. }
  338. #endif /* !WIN32 */
  339.  
  340. /* return the local port a socket is bound to */
  341. unsigned short
  342. get_local_port (int fd)
  343. {
  344.     struct sockaddr_in sin;
  345.     socklen_t sinsize = sizeof (sin);
  346.  
  347.     if (getsockname (fd, (struct sockaddr *) &sin, &sinsize))
  348.     {
  349.         nlogerr ("get_local_port", "getsockname");
  350.         return 0;
  351.     }
  352.     return (ntohs (sin.sin_port));
  353. }
  354.  
  355. /* table used for is_address */
  356. static unsigned long cidr_to_bitmask[] = {
  357.     /* 00 */ 0x00000000,
  358.     /* 01 */ 0x80000000,
  359.     /* 02 */ 0xC0000000,
  360.     /* 03 */ 0xE0000000,
  361.     /* 04 */ 0xF0000000,
  362.     /* 05 */ 0xF8000000,
  363.     /* 06 */ 0xFC000000,
  364.     /* 07 */ 0xFE000000,
  365.     /* 08 */ 0xFF000000,
  366.     /* 09 */ 0xFF800000,
  367.     /* 10 */ 0xFFC00000,
  368.     /* 11 */ 0xFFE00000,
  369.     /* 12 */ 0xFFF00000,
  370.     /* 13 */ 0xFFF80000,
  371.     /* 14 */ 0xFFFC0000,
  372.     /* 15 */ 0xFFFE0000,
  373.     /* 16 */ 0xFFFF0000,
  374.     /* 17 */ 0xFFFF8000,
  375.     /* 18 */ 0xFFFFC000,
  376.     /* 19 */ 0xFFFFE000,
  377.     /* 20 */ 0xFFFFF000,
  378.     /* 21 */ 0xFFFFF800,
  379.     /* 22 */ 0xFFFFFC00,
  380.     /* 23 */ 0xFFFFFE00,
  381.     /* 24 */ 0xFFFFFF00,
  382.     /* 25 */ 0xFFFFFF80,
  383.     /* 26 */ 0xFFFFFFC0,
  384.     /* 27 */ 0xFFFFFFE0,
  385.     /* 28 */ 0xFFFFFFF0,
  386.     /* 29 */ 0xFFFFFFF8,
  387.     /* 30 */ 0xFFFFFFFC,
  388.     /* 31 */ 0xFFFFFFFE,
  389.     /* 32 */ 0xFFFFFFFF
  390. };
  391.  
  392. #if 0
  393. static int
  394. bitmask_to_cidr (unsigned int bitmask)
  395. {
  396.     int i;
  397.     for (i = 0; i < 33; i++)
  398.         if (cidr_to_bitmask[i] == bitmask)
  399.             return i;
  400.     return -1;
  401. }
  402. #endif
  403.  
  404. /*
  405.  * is_address
  406.  *
  407.  * inputs        - hostname
  408.  *                - pointer to ip result
  409.  *                - pointer to ip_mask result
  410.  * output        - YES if hostname is ip# only NO if its not
  411.  *              - 
  412.  * side effects        - NONE
  413.  * 
  414.  * Thanks Soleil
  415.  * Borrowed from hybrid6 ircd source which is under GNU license.
  416.  *
  417.  * BUGS
  418.  */
  419.  
  420. int
  421. is_address (char *host, unsigned int *ip_ptr, unsigned int *ip_mask_ptr)
  422. {
  423.     unsigned int current_ip = 0;
  424.     unsigned int octet = 0;
  425.     int     found_mask = 0;
  426.     int     dot_count = 0;
  427.     char    c;
  428.  
  429.     while ((c = *host))
  430.     {
  431.         if (isdigit (c))
  432.         {
  433.             octet *= 10;
  434.             octet += (*host & 0xF);
  435.         }
  436.         else if (c == '.')
  437.         {
  438.             current_ip <<= 8;
  439.             current_ip += octet;
  440.             if (octet > 255)
  441.                 return 0;
  442.             octet = 0;
  443.             dot_count++;
  444.         }
  445.         else if (c == '/')
  446.         {
  447.             if (octet > 255)
  448.                 return 0;
  449.             found_mask = 1;
  450.             while (dot_count <= 3)
  451.             {
  452.                 current_ip <<= 8;
  453.                 current_ip += octet;
  454.                 octet = 0;
  455.                 dot_count++;
  456.             }
  457.             *ip_ptr = BSWAP32 (ntohl (current_ip));
  458.             current_ip = 0L;
  459.         }
  460.         else if (c == '*')
  461.         {
  462.             if ((dot_count == 3) && (*(host + 1) == '\0')
  463.                 && (*(host - 1) == '.'))
  464.             {
  465.                 while (dot_count <= 3)
  466.                 {
  467.                     current_ip <<= 8;
  468.                     dot_count++;
  469.                 }
  470.                 *ip_ptr = BSWAP32 (ntohl (current_ip));
  471.                 *ip_mask_ptr = BSWAP32 (ntohl (0xFFFFFF00L));
  472.                 return 1;
  473.             }
  474.             else
  475.                 return 0;
  476.         }
  477.         else
  478.             return 0;
  479.         host++;
  480.     }
  481.  
  482.     if (found_mask)
  483.     {
  484.         current_ip <<= 8;
  485.         current_ip += octet;
  486.         if (current_ip > 32)
  487.             *ip_mask_ptr = BSWAP32 (ntohl (current_ip));
  488.         else
  489.             *ip_mask_ptr = BSWAP32 (ntohl (cidr_to_bitmask[current_ip]));
  490.     }
  491.     else
  492.     {
  493.         while (dot_count <= 3)
  494.         {
  495.             current_ip <<= 8;
  496.             current_ip += octet;
  497.             octet = 0;
  498.             dot_count++;
  499.         }
  500.         *ip_ptr = BSWAP32 (ntohl (current_ip));
  501.         *ip_mask_ptr = 0xffffffff;
  502.     }
  503.     return 1;
  504. }
  505.